跳到主要内容

Docker 操作容器

容器执行的原理

这里以运行一个 Busybox 容器为例,介绍下 Docker 的工作原理

提示

BusyBox 是打包为单个二进制文件的核心 Unix 实用程序的集合。这使其成为资源受限环境(例如嵌入式设备)的理想选择。完整的发行版包含近 400 个最常用的命令,而所有这一切功能却只有区区 1M 左右的大小。

以下执行通过 Busybox 镜像打印 hello world

docker run busybox echo "hello world"

背后的原理

首先 Docker 会检查 busybox latest 镜像是否己经存在于本机,如果没有则先去镜像中心拉取这个镜像并执行

命令一览

下面所有操作都需要 root 权限,所以下面就省的写 sudo

基本命令 image.png

查看容器

# 查看当前启动的容器
docker ps

# 查看所有容器(包括没有启动的)
docker ps -a

创建 交互式 容器

所需要的命令主要为 docker run

例如,下面的命令输出一个 “Hello World”,之后终止容器。

$ docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world

这跟在本地直接执行 /bin/echo 'hello world' 几乎感觉不出任何区别。

加入 -i 参数启动交互式容器之后是直接进入容器终端,可以查看容器的文件结构

# -t 为容器重新分配一个伪输入终端, -i 以交互模式运行容器, 通常与 -t 同时使用
docker run -it

# 添加名字
docker run -it --name=my01

# 指定依赖于某个镜像运行(例如这里的 ubuntu)
# 注意:因为容器是依托于镜像运行的,所以必须指定一个镜像
docker run -it --name=my01 ubuntu

# 指定一个解析命令的 shell(具体看 Linux学习01)
docker run -it --name=my01 ubuntu /bin/bash
# 注:实际上这个 bash 是一个阉割版的 bash,所以它没有 ll 这个命令,只能使用 ls

# 退出容器
exit

使用 exit 命令则是直接退出容器并停止容器终端

创建 守护式 容器

直接进入命令行的是交互式容器,挂后台关闭终端不会停止的是守护式容器

# 使用 -d 是创建守护式容器
# 注意这个容器的名字不能相同,且因为是挂后台的,所以可以不加上 bash,但是别忘了加上镜像
docker run -d --name=my02 ubuntu

# 启动守护式容器后再进入容器(使用 exit 退出也不会导致守护容器退出)
docker exec -it my02 /bin/bash

# 停止容器
docker stop my02

注: 容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关。

使用 -d 参数启动后会返回一个唯一的 id,也可以通过 docker container ls 命令来查看容器信息。

$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77b2dc01fe0f ubuntu:18.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright

要获取容器的输出信息,可以通过 docker container logs 命令。

$ docker container logs [container ID or NAMES]
hello world
hello world
hello world
. . .

停止、启动、进入容器

可以使用 docker container stop [container ID or NAMES] 来终止一个运行中的容器。

此外,当 Docker 容器中指定的应用终结时,容器也自动终止。

终止状态的容器可以用 docker container ls -a 命令看到。例如:

$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ba267838cc1b ubuntu:18.04 "/bin/bash" 30 minutes ago Exited (0) About a minute ago trusting_newton

使用例:

# 停止容器
docker container stop my02

# 启动容器
docker container start my02

# 进入正在运行的容器,开启一个新的终端
docker exec -it my02 /bin/bash

# 进入正在运行的容器(就是第一次创建的那个进程),且退出后会关闭容器(exit)
docker attach my02

# 列出所有的容器 ID
docker ps -aq

# 停止所有的容器
docker stop $(docker ps -aq)

# 删除所有的容器
docker rm $(docker ps -aq)

docker 在容器外执行某个容器内的某个命令

docker exec -it $DOCKER_ID /bin/bash -c 'cd /packages/detectron && python tools/train.py'

开机自启、取消自启

# 启动容器时,加上这个参数表示开机自启
docker run –restart=always

# 如果已经启动了则使用 update 命令进行修改,使其开机自启
docker update –restart=always <CONTAINER ID>

# 取消掉开机自启
docker update –restart=no <CONTAINER ID>

查看容器 ip 地址

因为一个容器实际上就是一个“虚拟机”,所以一般 docker 会给其一个虚拟的 ip,然后再把这个 ip 和宿主机的某个端口进行映射,使之能访问到容器

# 通过 docker inspect 可以查看容器运行的各种数据
docker inspect my03

导出和导入容器

如果要导出本地某个容器,可以使用 docker export 命令。

$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7691a814370e ubuntu:18.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test

$ docker export 7691a814370e > ubuntu.tar

这样将导出容器快照到本地文件。

可以使用 docker import 从容器快照文件中再导入为镜像,例如

$ cat ubuntu.tar | docker import - test/ubuntu:v1.0
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB

此外,也可以通过指定 URL 或者某个目录来导入,例如

$ docker import http://example.com/exampleimage.tgz example/imagerepo

注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

删除容器

可以使用 docker container rm 来删除一个处于终止状态的容器。例如

$ docker container rm trusting_newton
trusting_newton

如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。

清理所有处于终止状态的容器

docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。

$ docker container prune

使用例如下:

# 使用 rm 删除(运行中是无法删除的)
docker container rm my03

# 删除全部
docker container prune

# 再通过 -a 来查看会发现已经没有那个容器了
docker ps -a

Docker 容器显示日志

docker logs 容器名

参数:

 --details        显示更多的信息
-f, --follow 跟踪实时日志
--since string 显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
--tail string 从日志末尾显示多少行日志, 默认是all
-t, --timestamps 显示时间戳
--until string 显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)

问题解决

端口问题启动失败

Docker SQL bind: An attempt was made to access a socket in a way forbidden by its access permissions

netsh int ipv4 show excludedportrange protocol=tcp

检查 hyper-v 的端口

最简单的方法,重启网络(管理员权限)

net stop winnat
net start winnat